package firbi.base;


import android.app.Instrumentation;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.test.ActivityInstrumentationTestCase2;
import android.view.KeyEvent;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;

/**
 * Instrumentation test meant to exercise the search bar. It goes through
 * various user inputs and tests whether the correct activity was called as
 * a result.  
 * Can be run with the following command:
 * adb shell am instrument \
 * 	-e class firbi.base.SearchTestSearchBar \
 *	-w firbi.base.tests/android.test.InstrumentationTestRunner
 *
 */
public class SearchTestSearchBar extends ActivityInstrumentationTestCase2<Search> {
	private Location mLoc;
	private Search activity;
	private int mRouteCount;
	private int mStopCount;
	private Instrumentation.ActivityMonitor mMonitorRoute;
	private Instrumentation.ActivityMonitor mMonitorStop;
	

	public SearchTestSearchBar() {
		super("firbi.base", Search.class);
	}

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		mRouteCount = 0;
		mStopCount = 0;
		mLoc = new Location(LocationManager.GPS_PROVIDER);
		mLoc.setLatitude( 47.6198d );
		mLoc.setLongitude( -122.347d );
		activity = getActivity();
		LocationManager locMan = (LocationManager)activity.getSystemService(Context.LOCATION_SERVICE);
    	locMan.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);
    	locMan.setTestProviderLocation(LocationManager.GPS_PROVIDER, mLoc);
	}
	/**
	 * This tests exercises the search bar by accepting both invalid and valid input.
	 * The test checks to make sure the corresponding RouteView and StopView are only
	 * called when correct input is passed.
	 */
	public void testSearchBar() throws Exception{
		MapView myMap = (MapView) getActivity().findViewById(R.id.map);
		int oldZoom = myMap.getZoomLevel();
    	GeoPoint oldCenter = myMap.getMapCenter();
    	
		mMonitorRoute = new Instrumentation.ActivityMonitor("firbi.base.RouteView", null, true);
		mMonitorStop = new Instrumentation.ActivityMonitor("firbi.base.StopView", null, true);
		this.getInstrumentation().addMonitor(mMonitorRoute);
		this.getInstrumentation().addMonitor(mMonitorStop);
		/* Valid route entry -- route should have been called, stop not called */
		sendKeys("7");
		Thread.sleep(500);
		sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
		Thread.sleep(500);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    	while (!getActivity().getFlag());
    	mRouteCount++;
    	assertEquals("Go to Route1", mRouteCount, mMonitorRoute.getHits());
    	assertEquals("No to stop1", mStopCount, mMonitorStop.getHits());
    	
    	Thread.sleep(500);
    	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
    	deleteText(1);
    	
    	/* Valid route entry -- route should have been called, stop not called*/
    	sendKeys("5 5 0");
    	mRouteCount++;
		sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    	while (!getActivity().getFlag());
    	assertEquals("Go to Route2", mRouteCount, mMonitorRoute.getHits());
    	assertEquals("No to stop2", mStopCount, mMonitorStop.getHits());
    	Thread.sleep(500);
    	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
    	Thread.sleep(300);
    	deleteText(3);
    	
    	/* Invalid route entry -- neither should have been called */
    	sendKeys("9 9 9");
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    	while (!getActivity().getFlag());
    	assertEquals("No to route3", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("No to stop3", mStopCount, mMonitorStop.getHits());
    	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
    	Thread.sleep(300);
    	deleteText(3);
    	
    	/* Switch to list */
     	sendKeys(KeyEvent.KEYCODE_MENU);
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	sendKeys("ENTER");
    	
    	/* Invalid bus stop number -- neither should have been called */
    	sendKeys("1 2 3 4 5");
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    	while (!getActivity().getFlag());
    	assertEquals("No to route4", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("No to stop4", mStopCount, mMonitorStop.getHits());
    	Thread.sleep(500);
    	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
    	Thread.sleep(300);
    	deleteText(5);
    	
    	/* Valid bus stop number -- only stop should have been called */
    	sendKeys("7 5 4 1 4");
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    	while (!getActivity().getFlag());
    	mStopCount++;
    	assertEquals("No to route5", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("Go to stop5", mStopCount, mMonitorStop.getHits());
    	Thread.sleep(500);
    	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
    	Thread.sleep(300);
    	deleteText(5);
    	
    	/* Blank input */
    	sendKeys("ENTER");
    	Thread.sleep(500);
    	assertEquals("No to route6", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("No to stop6", mStopCount, mMonitorStop.getHits());
    	
    	/* Make sure bus stops have not changed due to route/bus stop input */
    	assertNull("Currently no bus stop", getActivity().getCurrentBusStops());
    	
    	/* Switch to list */
     	sendKeys(KeyEvent.KEYCODE_MENU);
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	sendKeys("ENTER"); 
      	
    	/* Invalid address -- neither should have been called */
    	sendKeys("1 2 3 4");
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys("P I N E A P P L E");
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys("L A N E");
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(800);
      	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
      	Thread.sleep(300);
    	deleteText(19);
    	assertEquals("No to route7", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("No to stop7", mStopCount, mMonitorStop.getHits());
    	assertNull("No stops found7", getActivity().getCurrentBusStops());
    	
    	/* None of these inputs should have changed the map */
    	boolean zoomEquals = (oldZoom==myMap.getZoomLevel());
    	boolean centerEquals = (oldCenter.equals(myMap.getMapCenter()));
    	assertTrue("Center unchanged" , centerEquals);
    	assertTrue("Zoom unchanged", zoomEquals);
    	
  
    	/* Valid address -- neither should have been called */
    	sendKeys("4 T H");
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys("A V E");
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys("N E");
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    	while (!getActivity().getFlag());
    	Thread.sleep(3000);
    	/* Map should have zoomed into address */
    	zoomEquals = (oldZoom==myMap.getZoomLevel());
    	centerEquals = (oldCenter.equals(myMap.getMapCenter()));
    	assertFalse("Center changed address", centerEquals);
    	assertFalse("Zoom changed address", zoomEquals);
    	assertEquals("No to route8", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("No to stop8", mStopCount, mMonitorStop.getHits());
    	assertNotNull("Found stops8", getActivity().getCurrentBusStops());
    	Thread.sleep(500);
    	sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
    	Thread.sleep(300);
    	deleteText(11);
   
    	/* Space does nothing */
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys(KeyEvent.KEYCODE_SPACE);
    	sendKeys("ENTER");
    	Thread.sleep(500);
    	assertEquals("No to route9", mRouteCount, mMonitorRoute.getHits());	
    	assertEquals("No to stop9", mStopCount, mMonitorStop.getHits());
	}
	
	/**
	 * Tests the menu by checking if favorites is called
	 * when the user selects favorites.
	 * @throws Exception
	 */
	public void testMenu() throws Exception {
		Instrumentation.ActivityMonitor monitorFav = new Instrumentation.ActivityMonitor("firbi.base.Favorites", null, true);
		this.getInstrumentation().addMonitor(monitorFav);
		assertEquals("NO favorites", 0, monitorFav.getHits());
		Thread.sleep(1000);
		sendKeys(KeyEvent.KEYCODE_MENU);
		sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
		sendKeys("ENTER");
		Thread.sleep(1000);
		assertEquals("Yes to favorites", 1, monitorFav.getHits());
	}
	
	/** Deletes the text from the search bar
	 * 
	 * @param size: Number of characters to delete
	 */
	private void deleteText(int size) {
		for (int i = 0; i < size; i++) {
			sendKeys(KeyEvent.KEYCODE_DEL);
		}
		
	}
}
